package org.jeecg.modules.paycenter.channel.bankdocking.service;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.printing.PDFPrintable;
import org.apache.pdfbox.printing.Scaling;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.paycenter.channel.bankdocking.dto.Acc;
import org.jeecg.modules.paycenter.channel.bankdocking.dto.Cmp;
import org.jeecg.modules.paycenter.channel.bankdocking.dto.RespPacket;
import org.jeecg.modules.paycenter.channel.bankdocking.utils.BankUtils;
import org.jeecg.modules.paycenter.channel.bankdocking.utils.BatchDownFilesUtils;
import org.jeecg.modules.paycenter.exception.BankReceiveException;
import org.jeecg.modules.paycenter.exception.BankSendException;
import org.jeecg.modules.paycenter.dto.PayBillData;
import org.jeecg.modules.paycenter.service.BaseBankService;
import org.jeecg.modules.third.digitalseal.utils.PdfToImageUtil;
import org.jeecg.modules.wlhy.bill.entity.*;
import org.jeecg.modules.wlhy.company.entity.HyCompany;
import org.jeecg.modules.wlhy.customer.entity.HyCustomerAccountBook;
import org.jeecg.modules.wlhy.hycarrier.entity.HyCarrier;
import org.jeecg.modules.wlhy.hycarrier.entity.HyCarrierAccountBook;
import org.jeecg.modules.wlhy.hycarrier.entity.HyCarrierBank;
import org.jeecg.modules.wlhy.hycarrier.service.IHyCarrierAccountBookService;
import org.jeecg.modules.wlhy.hyconfig.entity.HyConfig;
import org.jeecg.modules.wlhy.hydriver.entity.HyDriver;
import org.jeecg.modules.wlhy.hydriver.entity.HyDriverAccountBook;
import org.jeecg.modules.wlhy.hydriver.service.IHyDriverAccountBookService;
import org.jeecg.modules.wlhy.hydriverbank.entity.HyDriverBank;
import org.jeecg.modules.wlhy.hyplatform.entity.HyPlatformAccountBook;
import org.jeecg.modules.wlhy.hyplatform.entity.HyPlatformBank;
import org.jeecg.modules.wlhy.hyplatform.entity.HyPlatformBill;
import org.jeecg.modules.wlhy.hyplatform.service.IHyPlatformAccountBookService;
import org.jeecg.modules.wlhy.hyplatform.service.IHyPlatformBillService;
import org.jeecg.modules.wlhy.shipping.entity.HyShippingNote;
import org.jeecg.modules.wlhy.utils.CodeUtil;
import org.jeecg.modules.wlhy.utils.HyConfigUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.standard.*;
import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.PrinterJob;
import java.io.*;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Slf4j
public class NhBankService extends BaseBankService {
    public static final String CHANNEL = "1";
    //银行文件路径
    @Value(value = "${jeecg.path.bank}")
    private String bankPath;

    @Autowired
    private BankUtils bankUtils;

    @Autowired
    private IHyDriverAccountBookService hyDriverAccountBookService;

    @Autowired
    private IHyPlatformAccountBookService hyPlatformAccountBookService;

    @Autowired
    private IHyCarrierAccountBookService hyCarrierAccountBookService;

    @Autowired
    private IHyPlatformBillService hyPlatformBillService;

    //region 钱包

    //获取农行钱包（余额、账户状态等）
    public Acc getAccBookInfo(String accNo, String logAccNo, String prov) {
        try {
            RespPacket packet = bankUtils.getAccountBookBalance(accNo, prov, logAccNo);
            if (packet.isSuccess()) {
                return packet.getAcc();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public HyCarrierAccountBook getCarriderAccBookInfo(HyCarrierAccountBook accountBook) {
        Acc acc = this.getAccBookInfo(accountBook.getAccNo(), accountBook.getLogAccNo(), accountBook.getProv());
        if (acc != null) {
            accountBook.setAccSts(acc.getAccSts());
            accountBook.setAvailBal(acc.getAvailBal());

        } else {
            accountBook.setAccSts("-99");
            accountBook.setAvailBal(BigDecimal.ZERO);
        }
        return accountBook;
    }

    @Transactional
    public void addCarrierAccountBook(HyCarrier carrier) {
        HyConfig config = HyConfigUtils.getConfig();
        if (!config.getNhbankIzUse()) {
            throw new JeecgBootException("未开通服务");
        }
        HyCarrierAccountBook accountBook = new HyCarrierAccountBook();
        String logAccNo = hyCarrierAccountBookService.createLogAccNo();
        String logAccName = carrier.getCarrierName();
        accountBook.setCarrierId(carrier.getId());
        accountBook.setCustomerId(carrier.getCustomerId());
//        accountBook.setUserId(carrier.getUserId());
        accountBook.setAccNo(config.getNhbankAccno());
        accountBook.setProv(config.getNhbankProv());
        accountBook.setLogAccName(logAccName);
        accountBook.setLogAccNo(logAccNo);

        if (hyCarrierAccountBookService.save(accountBook)) {
            try {
                RespPacket packet = bankUtils.AddAccountBook(logAccName, logAccNo);
                if (!packet.isSuccess()) {
                    throw new JeecgBootException(packet.getRespInfo());
                }
            } catch (Exception e) {
                throw new JeecgBootException(e.getMessage());
            }
        } else {
            throw new JeecgBootException("添加失败");
        }
    }

    public HyDriverAccountBook getDriverAccBookInfo(HyDriverAccountBook accountBook) {
        Acc acc = this.getAccBookInfo(accountBook.getAccNo(), accountBook.getLogAccNo(), accountBook.getProv());
        if (acc != null) {
            accountBook.setAccSts(acc.getAccSts());
            accountBook.setAvailBal(acc.getAvailBal());

        } else {
            accountBook.setAccSts("-99");
            accountBook.setAvailBal(BigDecimal.ZERO);
        }
        return accountBook;
    }

    //检查平台农行垫付账户
    public Result<?> checkPlatformAcc(BigDecimal totalAmt) {
        //验证支付
        HyPlatformAccountBook platformAccountBook = hyPlatformAccountBookService.getAccountBook();
        if (platformAccountBook == null) {
            return Result.error("尚未开通钱包功能!");
        }

        //检查是否够支付
        Acc platformAcc = hyPlatformAccountBookService.getAcc(platformAccountBook);
        if (platformAcc == null) {
            return Result.error("查询平台钱包余额失败");
        }
        //可用余额
        BigDecimal availBal = platformAcc.getAvailBal();
        if (totalAmt.compareTo(availBal) == 1) {
            return Result.error("账户余额不足");
        }
        return Result.OK(platformAccountBook);
    }

    //endregion

    //region 电子回单
    //根据账户明细文件解析查询电子回单相关参数
    private List<String> getInfoByAccDetailFile(String filePath, String billNum, BigDecimal amt) {
        //对交易金额保留两位小数
        String amtStr = amt.setScale(2, BigDecimal.ROUND_HALF_DOWN).toString();
        log.info("解析查询电子回单相关参数 getJrnNoByAccDetailFile 参数：filePath|{}，billNum|{}, amt|{}", filePath, billNum, amtStr);
        List<String> infoList = new ArrayList<>();
        try {
            String encoding = "GBK";
            File file = new File(filePath);
            if (file.isFile() && file.exists()) { //判断文件是否存在
                InputStreamReader read = new InputStreamReader(new FileInputStream(file), encoding);//考虑到编码格式
                BufferedReader bufferedReader = new BufferedReader(read);
                String lineTxt = null;
                while ((lineTxt = bufferedReader.readLine()) != null) {
                    //省市代码|账号|货币码|交易日期|交易时间|日志号|交易类型|交易行号|户名|发生额标志|
                    // 对方账号省市代码|对方账号|对方账号货币码|对方账号户名|对方账号开户行|现转标志|
                    // 错账日期|错账传票号|交易金额|账户余额|上笔余额|其他费用总额|凭证种类|凭证省市代号|
                    // 凭证批次号|凭证号|客户参考号|交易码|柜员号|传票号|摘要|附言|交易来源|
                    // 遍历明细找出对应日志号
                    log.info("电子回单读取内容为："+lineTxt);
                    String[] detail = lineTxt.split("\\|");
                    // 日志号5 交易金额18 客户参考号26(流水号)
                    if (detail[26].equals(billNum) && detail[18].equals(amtStr)) {
                        infoList.add(detail[0]);//省市代码
                        infoList.add(detail[1]);//账号
                        infoList.add(detail[2]);//货币码
                        infoList.add(detail[3]);//交易日期
                        infoList.add(detail[5]);//日志号

                        infoList.add(detail[10]);//对方账号省市代码
                        infoList.add(detail[11]);//对方账号
                        infoList.add(detail[12]);//对方账号货币码

                        infoList.add(detail[18]);//交易金额
                        break;
                    }
                }
                read.close();
                //删除明细文件 节省空间
                if(infoList.size()>0){
                    file.delete();
                }
            } else {
                System.out.println("找不到指定的文件: " + filePath);
            }
        } catch (Exception e) {
            System.out.println("读取账户明细文件内容出错：" + filePath);
            e.printStackTrace();
        }
        return infoList;
    }



    //根据日志号找到对应电子回单文件 未用上
    private String getBankHdFileName(String dbProv, String dbAccNo, String date, String jrnNo) {
        File file = new File(bankPath);
        File[] fies = file.listFiles();
        String subfix = "CMRA76." + dbProv + dbAccNo + "_" + date + "_" + jrnNo;
//        log.info("自定义前缀：subfix|{}", subfix);
        for (File f : fies) {
            String fileName = f.getName();
//            log.info("文件名：fileName|{}", fileName);
            boolean isPdf = fileName.contains("pdf") || fileName.contains("PDF");
            if (isPdf && fileName.contains(subfix)) {
                return fileName;
            }
        }
        return null;
    }

    //查询银行回单(先查询账户明细，在明细文件中解析出对应一条银行流水的日志号，再去请求银行电子回单)
    public String queryBankHd(Date createTime, String dbProv, String dbAccNo, String billNum, BigDecimal amt) {
        log.info("queryBankHd参数：createTime|{}，dbProv|{}，dbAccNo|{}，billNum|{}, amt|{}", createTime, dbProv, dbAccNo, billNum, amt);
        SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMdd");
        String date = dateF.format(createTime);
        String timestamp = String.valueOf(createTime.getTime());

        //查询电子回单所需要的参数
        List<String> infoList = null;
        //查询账户明细
        try {
            log.info("查询账户明细参数：dbProv|{}，dbAccNo|{}，date|{}，timestamp|{}", dbProv, dbAccNo, date, timestamp);
            RespPacket packet = bankUtils.getAccountDetail(dbProv, dbAccNo, "01", date, date, timestamp);
            if (packet.isSuccess()) {
                if (packet.getFileFlag() == 1) {
                    Cmp cmp = packet.getCmp();
                    String filename = cmp.getBatchFileName();
                    String filepath = bankPath + File.separator + filename;
                    //解析日志号
                    infoList = this.getInfoByAccDetailFile(filepath, billNum, amt);
                    log.info("得到明细信息：{}", infoList);
                    if (infoList == null || infoList.size() == 0) {
                        throw new JeecgBootException("账户明细文件中不存在流水单号为【" + billNum + "】且交易金额为【" + amt + "】的记录！请检查参数是否填写正确！");
                    }
                } else {
                    throw new JeecgBootException("本条记录暂无明细，无法查询单子回单");
                }
            } else {
                throw new JeecgBootException(packet.getRespInfo());
            }
        } catch (Exception ex) {
            throw new JeecgBootException("查询账户明细失败，无法生成电子回单！" + ex.getMessage());
        }

        //查询电子回单
        try {
            log.info("查询电子回单参数：infoList|{}", infoList);
            RespPacket packet = bankUtils.getBankHd(
                    infoList.get(0), infoList.get(1), infoList.get(2), infoList.get(5),
                    infoList.get(6), infoList.get(7), infoList.get(3), infoList.get(4), new BigDecimal(infoList.get(8)));
            //延迟1秒后去查找文件
//            try
//            {
//                Thread.sleep(1000);
//                String filename = this.getBankHdFileName(dbProv, dbAccNo, date, jrnNo);
//                log.info("查询PDF文件名：filename|{}", filename);
//                if(filename != null){
//                    return Result.OK(filename);
//                }else{
//                    return Result.error("查询电子回单失败");
//                }
//            }
//            catch (InterruptedException e)
//            {
//                return Result.error("查询电子回单失败，延时失败");
//            }
            if (packet.isSuccess()) {
                if (packet.getFileFlag() == 1) {
                    Cmp cmp = packet.getCmp();
                    String filename = cmp.getBatchFileName();
                    //文件名去除后缀
                    String filenameNoSubfix = filename.substring(0, filename.lastIndexOf("."));
                    //回单pdf转jpg
                    String newFilename = PdfToImageUtil.bankHdPdf2Jpg(
                            bankPath + File.separator,
                            filenameNoSubfix,
                            bankPath + File.separator + date + File.separator);
                    if (newFilename == null) {
                        throw new JeecgBootException("电子回单PDF转图片失败！");
                    }
                    return date + File.separator + filename;
                } else {
                    throw new JeecgBootException("本条记录暂无回单");
                }
            } else {
                throw new JeecgBootException(packet.getRespInfo());
            }
        } catch (Exception ex) {
            throw new JeecgBootException("查询电子回单失败！" + ex.getMessage());
        }
    }


    //压缩 返回压缩包路径
    public String toZip(List<File> files) {
        String tempPath = "temp";
        File zipPath = new File(bankPath + File.separator + tempPath);
        if (!zipPath.exists()) {
            zipPath.mkdirs();//创建目录
        }
        String zipName = "银行电子回单_" + DateUtils.getDate("yyyyMMddHHmmss") + ".zip";
        File zipFile = new File(zipPath.getPath() + File.separator + zipName);
//        log.info("files: {}", files);
//        log.info("zipFile: {}", zipFile);
        BatchDownFilesUtils.toZip(files, zipFile);
        return tempPath + File.separator + zipName;
    }


    //合并pdf文件
    public String mergePdf(List<String> filenames) throws Exception {
        // pdf合并工具类
        PDFMergerUtility PDFmerger = new PDFMergerUtility();
        for (String filename : filenames) {
            // 要合成的文件
            PDFmerger.addSource(filename);
        }

        String tempPath = "temp";
        File mergePath = new File(bankPath + File.separator + tempPath);
        if (!mergePath.exists()) {
            mergePath.mkdirs();//创建目录
        }
        String mergeName = "批量电子回单_" + DateUtils.getDate("yyyyMMddHHmmss") + ".pdf";
        // 设置合并后要生成pdf文件
        PDFmerger.setDestinationFileName(mergePath + File.separator + mergeName);
        String savePath = tempPath + File.separator + mergeName;
        // 合并pdf
        try {
            PDFmerger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
        } catch (Exception e) {
            e.printStackTrace();
            throw new JeecgBootException("pdf文件合并失败");
        }
//        System.out.println("pdf文件合并成功");
        return savePath;
    }

    //打印完成后删除合并文件
    public void deleteMergePdfFile(String filename) {
        try {
            File file = new File(bankPath + File.separator + filename);
            if (file.isFile() && file.exists()) {
                file.delete();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new JeecgBootException("删除合并文件出错！" + filename);
        }
    }


    //后台打印功能 无用
    private PrintService getPrintService() {
        //查找所有的可用打印服务
        PrintService[] printServices = PrinterJob.lookupPrintServices();
        if (printServices == null || printServices.length == 0) {
            throw new JeecgBootException("未找到可用打印机，请检查!");
        }
        //定位默认的打印服务
        PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService();
        return defaultService;
    }

    //打印单个PDF
    public void printPDF(String fileName, PrintService printService) throws Exception {
        File file = new File(fileName);
        PDDocument document = null;
        try {
//            document = Loader.loadPDF(file);
            document = PDDocument.load(file);
            PrinterJob printJob = PrinterJob.getPrinterJob();
            printJob.setJobName(file.getName());
            //设置打印机
            printJob.setPrintService(printService);
            //设置纸张及缩放
            PDFPrintable pdfPrintable = new PDFPrintable(document, Scaling.SCALE_TO_FIT);
            //PageFormat类描述了要打印的页面的大小和方向。
            PageFormat pageFormat = new PageFormat();
            pageFormat.setOrientation(PageFormat.PORTRAIT);//设置打印方向 纵向
            //设置纸张
            Paper paper = new Paper();
            // 默认为A4纸张，对应像素宽和高分别为 595, 842
            int width = 595;
            int height = 842;
            paper.setSize(width, height);
            paper.setImageableArea(0, 0, width, height);
            pageFormat.setPaper(paper);//设置纸张
            //设置多页打印
            Book book = new Book();
            book.append(pdfPrintable, pageFormat, document.getNumberOfPages());
            printJob.setPageable(book);
            printJob.setCopies(1);//设置打印份数
            //添加打印属性
            HashPrintRequestAttributeSet pars = new HashPrintRequestAttributeSet();
            pars.add(MultipleDocumentHandling.SINGLE_DOCUMENT);//合并成一个文档
            pars.add(new NumberUp(2));//一纸两页
            //类PresentationDirection与NumberUp属性结合使用，以指示要在所选介质的实例的单面上施加的多个打印流页面的布局。
            pars.add(PresentationDirection.TORIGHT_TOBOTTOM);
            pars.add(Sides.ONE_SIDED); //设置单双页
            pars.add(MediaSizeName.ISO_A4); //设置A4纸
            pars.add(Finishings.STAPLE);
//            pars.add(new MediaPrintableArea(0f,0f,210f, 297f, MediaPrintableArea.MM));

            pars.add(DialogTypeSelection.NATIVE);
            printJob.printDialog();
            printJob.print();
        } finally {
            if (document != null) {
                try {
                    document.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //打印多个PDF
    public void printMultiPDF(List<String> fileNames) throws Exception {
        PrintService service = getPrintService();
        for (int i = 0; i < fileNames.size(); i++) {
            printPDF(fileNames.get(i), service);
        }
    }

    public void downloadBankNo(String bankName, String bankType) {
        try {
            RespPacket packet = bankUtils.downloadBankNo(bankName, bankType);

        } catch (Exception e) {

        }
    }
//endregion

    //region

    private RespPacket getExchangeStatus(String billNum) {
        try {
            RespPacket exchangeStatus = bankUtils.getExchangeStatus(billNum);
            return exchangeStatus;
        } catch (Exception e) {
            return null;
        }
    }

    public Result tx(HyDriverAccountBook accountBook ,HyDriver driver, String driverBankId, BigDecimal amt) {

        //验证卡号
        HyDriverBank driverBank = hyDriverBankService.getById(driverBankId);
        if (driverBank == null) {
            return Result.error("未获取到银行卡信息！");
        }
        if (!StringUtils.equals(driverBank.getDriverId(), driver.getId())) {
            return Result.error("银行卡信息错误！");
        }

        String crAccName = driverBank.getBankName();
        String crAccNo = driverBank.getBankNum();

        RespPacket packet = null;
        String accNo = accountBook.getAccNo();
        String logAccNo = accountBook.getLogAccNo();
        String lsd = CodeUtil.getBillNum();

        HyDriverBill driverBill = new HyDriverBill();
        driverBill.setBillNum(lsd);
        driverBill.setBillType("2");//提现
        driverBill.setDriverId(driver.getId());
        driverBill.setDbaccno(accNo);
        HyConfig config = HyConfigUtils.getConfig();
        //
        driverBill.setDbaccname(config.getNhbankAccName());
        driverBill.setDblogaccno(logAccNo);
        driverBill.setCraccno(crAccNo);
        driverBill.setCraccname(crAccName);
        driverBill.setCrlogaccno("");
        driverBill.setAmt(amt); //提现金额
        driverBill.setRespSource("0");
        driverBill.setRespCode("4");
        driverBill.setRespInfo("交易成功");
        driverBill.setPayChannel(CHANNEL);

        try {
            packet = bankUtils.tx(
                    lsd, accountBook.getProv(), "",
                    accNo, logAccNo, accountBook.getLogAccName(),
                    crAccNo, crAccName, amt, driverBank.getBankType());
            if (packet.isSuccess()) {
                //添加司机流水单
                hyDriverBillService.save(driverBill);
                return Result.OK("操作成功！");
            } else {
                driverBill.setRespSource(packet.getRespSource());
                driverBill.setRespCode(packet.getRespCode());
                driverBill.setRespInfo(packet.getRespInfo());
                driverBill.setRxtInfo(packet.getRxtInfo());
            }
            //return Result.error(packet.getRespInfo());
        } catch (BankSendException e) {
            return Result.error("发起交易超时,请重试！");
        } catch (BankReceiveException e) {
            //发送成功，但是接收数据后续处理异常
            driverBill.setRespSource("-1");
            driverBill.setRespCode("-1");
            driverBill.setRespInfo("接收交易数据超时,请查询交易状态");
            driverBill.setRxtInfo("");
        } catch (Exception e) {
            return Result.error("提现失败," + e.getMessage());
        }

        //查询交易状态
        RespPacket exchangeStatus = getExchangeStatus(lsd);
        String msg = "交易失败";
        if (exchangeStatus != null) {
            if (exchangeStatus.isSuccess()) {
                String transSta = exchangeStatus.getTransSta();
                if ("4".equals(transSta)) {
                    driverBill.setRespSource("0");
                    driverBill.setRespCode("4");
                    driverBill.setRespInfo("交易成功");
                    driverBill.setRxtInfo("");
                    hyDriverBillService.save(driverBill);
                    return Result.OK("操作成功！");
                } else {
                    Cmp cmp = exchangeStatus.getCmp();
                    if (cmp != null) {
                        String rm =  cmp.getRespPrvData();
                        if(StringUtils.isNotEmpty(rm)) {
                            driverBill.setRespInfo(rm);
                            msg = rm;
                        }
                    }
                    driverBill.setRespSource(transSta);
                }
            }
        }
        hyDriverBillService.save(driverBill);
        return Result.error(msg);
    }

    public Result tx(HyDriver driver, String driverBankId, BigDecimal amt) {
        HyDriverAccountBook accountBook = hyDriverAccountBookService.getOne(
                new QueryWrapper<HyDriverAccountBook>().eq("driver_id", driver.getId())
        );
        if (accountBook == null) {
            return Result.error("未获取到账户信息！");
        }
        //验证卡号
        HyDriverBank driverBank = hyDriverBankService.getById(driverBankId);
        if (driverBank == null) {
            return Result.error("未获取到银行卡信息！");
        }
        if (!StringUtils.equals(driverBank.getDriverId(), driver.getId())) {
            return Result.error("银行卡信息错误！");
        }

        String crAccName = driverBank.getBankName();
        String crAccNo = driverBank.getBankNum();

        RespPacket packet = null;
        String accNo = accountBook.getAccNo();
        String logAccNo = accountBook.getLogAccNo();
        String lsd = CodeUtil.getBillNum();

        HyDriverBill driverBill = new HyDriverBill();
        driverBill.setBillNum(lsd);
        driverBill.setBillType("2");//提现
        driverBill.setDriverId(driver.getId());
        driverBill.setDbaccno(accNo);
        HyConfig config = HyConfigUtils.getConfig();
        driverBill.setDbaccname(config.getNhbankAccName());
        driverBill.setDblogaccno(logAccNo);
        driverBill.setCraccno(crAccNo);
        driverBill.setCraccname(crAccName);
        driverBill.setCrlogaccno("");
        driverBill.setAmt(amt); //提现金额
        driverBill.setRespSource("0");
        driverBill.setRespCode("4");
        driverBill.setRespInfo("交易成功");
        driverBill.setPayChannel(CHANNEL);

        try {
            packet = bankUtils.tx(
                    lsd, accountBook.getProv(), "",
                    accNo, logAccNo, accountBook.getLogAccName(),
                    crAccNo, crAccName, amt, driverBank.getBankType());
            if (packet.isSuccess()) {
                //添加司机流水单
                hyDriverBillService.save(driverBill);
                return Result.OK("操作成功！");
            } else {
                driverBill.setRespSource(packet.getRespSource());
                driverBill.setRespCode(packet.getRespCode());
                driverBill.setRespInfo(packet.getRespInfo());
                driverBill.setRxtInfo(packet.getRxtInfo());
            }
            //return Result.error(packet.getRespInfo());
        } catch (BankSendException e) {
            return Result.error("发起交易超时,请重试！");
        } catch (BankReceiveException e) {
            //发送成功，但是接收数据后续处理异常
            driverBill.setRespSource("-1");
            driverBill.setRespCode("-1");
            driverBill.setRespInfo("接收交易数据超时,请查询交易状态");
            driverBill.setRxtInfo("");
        } catch (Exception e) {
            return Result.error("提现失败," + e.getMessage());
        }

        //查询交易状态
        RespPacket exchangeStatus = getExchangeStatus(lsd);
        String msg = "交易失败";
        if (exchangeStatus != null) {
            if (exchangeStatus.isSuccess()) {
                String transSta = exchangeStatus.getTransSta();
                if ("4".equals(transSta)) {
                    driverBill.setRespSource("0");
                    driverBill.setRespCode("4");
                    driverBill.setRespInfo("交易成功");
                    driverBill.setRxtInfo("");
                    hyDriverBillService.save(driverBill);
                    return Result.OK("操作成功！");
                } else {
                    Cmp cmp = exchangeStatus.getCmp();
                    if (cmp != null) {
                        String rm =  cmp.getRespPrvData();
                        if(StringUtils.isNotEmpty(rm)) {
                            driverBill.setRespInfo(rm);
                            msg = rm;
                        }
                    }
                    driverBill.setRespSource(transSta);
                }
            }
        }
        hyDriverBillService.save(driverBill);
        return Result.error(msg);
    }

    public Result carrierTx(HyCarrierAccountBook accountBook, HyCarrier carrier, BigDecimal amt, HyCarrierBank carrierBank) {
        String crAccName = carrier.getBankName();
        String crAccNo = carrier.getBankNum();
        String bankType = carrier.getBankType();

        if (carrierBank != null) {
            crAccName = carrierBank.getBankName();
            crAccNo = carrierBank.getBankNum();
            bankType = carrierBank.getBankType();
        }

        RespPacket packet = null;
        String accNo = accountBook.getAccNo();
        String logAccNo = accountBook.getLogAccNo();
        String lsd = CodeUtil.getBillNum();


        HyCarrierBill carrierBill = new HyCarrierBill();
        carrierBill.setBillNum(lsd);
        carrierBill.setBillType("2");//提现
        carrierBill.setCarrierId(carrier.getId());

        carrierBill.setDbaccno(accNo);
        HyConfig config = HyConfigUtils.getConfig();
        carrierBill.setDbaccname(config.getNhbankAccName());
        carrierBill.setDblogaccno(logAccNo);
        carrierBill.setCraccno(crAccNo);
        carrierBill.setCraccname(crAccName);
        carrierBill.setCrlogaccno("");
        carrierBill.setAmt(amt); //提现金额
        carrierBill.setRespSource("0");
        carrierBill.setRespCode("4");
        carrierBill.setRespInfo("交易成功");
        carrierBill.setPayChannel(CHANNEL);

        try {
            packet = bankUtils.tx(
                    lsd, accountBook.getProv(), "",
                    accNo, logAccNo, accountBook.getLogAccName(),
                    crAccNo, crAccName, amt, bankType);
            if (packet.isSuccess()) {
                //添加司机流水单
                hyCarrierBillService.save(carrierBill);
                return Result.OK("操作成功！");
            } else {
                carrierBill.setRespSource(packet.getRespSource());
                carrierBill.setRespCode(packet.getRespCode());
                carrierBill.setRespInfo(packet.getRespInfo());
                carrierBill.setRxtInfo(packet.getRxtInfo());
            }
            //return Result.error(packet.getRespInfo());
        } catch (BankSendException e) {
            return Result.error("发起交易超时,请重试！");
        } catch (BankReceiveException e) {
            //发送成功，但是接收数据后续处理异常
            carrierBill.setRespSource("-1");
            carrierBill.setRespCode("-1");
            carrierBill.setRespInfo("接收交易数据超时,请查询交易状态");
            carrierBill.setRxtInfo("");
        } catch (Exception e) {
            return Result.error("提现失败," + e.getMessage());
        }

        //查询交易状态
        RespPacket exchangeStatus = getExchangeStatus(lsd);
        String msg = "交易失败";
        if (exchangeStatus != null) {
            if (exchangeStatus.isSuccess()) {
                String transSta = exchangeStatus.getTransSta();
                if ("4".equals(transSta)) {
                    carrierBill.setRespSource("0");
                    carrierBill.setRespCode("4");
                    carrierBill.setRespInfo("交易成功");
                    carrierBill.setRxtInfo("");
                    hyCarrierBillService.save(carrierBill);
                    return Result.OK("操作成功！");
                } else {
                    Cmp cmp = exchangeStatus.getCmp();
                    if (cmp != null) {
                        String rm =  cmp.getRespPrvData();
                        if(StringUtils.isNotEmpty(rm)) {
                            carrierBill.setRespInfo(rm);
                            msg = rm;
                        }
                    }
                    carrierBill.setRespSource(transSta);
                }
            }
        }
        hyCarrierBillService.save(carrierBill);
        return Result.error(msg);
    }

    public Result platformTx(HyPlatformAccountBook accountBook,BigDecimal amt , HyPlatformBank platformBank) {
        String crAccName = platformBank.getBankName();
        String crAccNo = platformBank.getBankNum();

        RespPacket packet = null;
        String accNo = accountBook.getAccNo();
        String logAccNo = accountBook.getLogAccNo();
        String lsd = CodeUtil.getBillNum();

        HyPlatformBill bill = new HyPlatformBill();
        bill.setBillNum(lsd);
        bill.setBillType("2");//提现
        bill.setDbaccno(accNo);
        bill.setDbaccname(accountBook.getLogAccName());
        bill.setDblogaccno(logAccNo);
        bill.setCraccno(crAccNo);
        bill.setCraccname(crAccName);
        bill.setCrlogaccno("");
        bill.setAmt(amt); //提现金额
        bill.setRespSource("0");
        bill.setRespCode("4");
        bill.setRespInfo("交易成功");
        bill.setPayChannel("1");
        bill.setPayChannel(NhBankService.CHANNEL);
        try {
            packet = bankUtils.tx(
                    lsd,accountBook.getProv(), "",
                    accNo, logAccNo, accountBook.getLogAccName(),
                    crAccNo, crAccName, amt,platformBank.getBankType());
            if(packet.isSuccess()){
                hyPlatformBillService.save(bill);
                return Result.OK("操作成功！");
            }
            bill.setRespSource(packet.getRespSource());
            bill.setRespCode(packet.getRespCode());
            bill.setRespInfo(packet.getRespInfo());
            bill.setRxtInfo(packet.getRxtInfo());
        }  catch (BankSendException e) {
            return Result.error("交易超时,请稍后重试！");
        } catch (BankReceiveException e) {
            //发送成功，但是接收数据后续处理异常
            bill.setRespSource("-1");
            bill.setRespCode("-1");
            bill.setRespInfo("接收交易数据超时,请查询交易状态");
            bill.setRxtInfo("");
        } catch (Exception e) {
            return Result.error("交易失败：" + e.getMessage());
        }
        //查询交易状态
        RespPacket exchangeStatus = getExchangeStatus(lsd);
        String msg = "交易失败";
        if (exchangeStatus != null) {
            if (exchangeStatus.isSuccess()) {
                String transSta = exchangeStatus.getTransSta();
                if ("4".equals(transSta)) {
                    bill.setRespSource("0");
                    bill.setRespCode("4");
                    bill.setRespInfo("交易成功");
                    bill.setRxtInfo("");
                    hyPlatformBillService.save(bill);
                    return Result.OK("操作成功！");
                }else {
                    Cmp cmp = exchangeStatus.getCmp();
                    if(cmp!=null){
                        String rm = cmp.getRespPrvData();
                        if (StringUtils.isNotEmpty(rm)) {
                            bill.setRespInfo(rm);
                            msg = rm;
                        }
                    }
                    bill.setRespSource(transSta);
                }
            }
        }
        hyPlatformBillService.save(bill);
        return Result.error(msg);
    }

    public Result<?> getDriverAccounts(Map<String, HyDriver> driverMaps) {
        Map<String, HyDriverAccountBook> driverAccountBookMaps = new HashMap<>();
        Set<String> driverSet = driverMaps.keySet();
        Collection<HyDriver> hyDrivers = driverMaps.values();
        List<HyDriverAccountBook> driverAccountBooks = hyDriverAccountBookService.getAccountBookByDriverIds(driverSet);
        for (HyDriverAccountBook driverAccountBook : driverAccountBooks) {
            driverAccountBookMaps.put(driverAccountBook.getDriverId(), driverAccountBook);
        }
        if (driverAccountBooks.size() != driverSet.size()) {
            List<String> noAccDriverList = new ArrayList<>();
            List<String> noAccDriverIdList = new ArrayList<>();
            for (HyDriver hyDriver : hyDrivers) {
                if (!driverAccountBookMaps.containsKey(hyDriver.getId())) {
                    noAccDriverList.add(hyDriver.getDriverName());
                    noAccDriverIdList.add(hyDriver.getId());
                }
            }
            return Result.error(-98,String.join(",", noAccDriverList) + ":等司机未开通钱包" , String.join(",", noAccDriverIdList));
        }
        return Result.OK(driverAccountBookMaps);
    }

    public Map<String, HyCarrierAccountBook> getCarrierAccounts(Map<String, HyCarrier> carrierMaps) {
        Map<String, HyCarrierAccountBook> carrierAccountBookHashMaps = new HashMap<>();//车队长钱包
        Set<String> carrierKeys = carrierMaps.keySet();
        for (String carrierId : carrierKeys) {
            HyCarrierAccountBook carrierAccountBook = hyCarrierAccountBookService.getAccountBookByCarrierId(carrierId);
            if (carrierAccountBook == null) {
                HyCarrier hyCarrier = carrierMaps.get(carrierId);
                throw new JeecgBootException("车队长:" + hyCarrier.getCarrierName() + ",未开通钱包");
            }
            carrierAccountBookHashMaps.put(carrierId, carrierAccountBook);
        }
        return carrierAccountBookHashMaps;
    }
    //endregion

    //region 支付订单

    public PayBillData setBillPayData(PayBillData payBillData ,
                                      HyCompany company,
                                      HyCustomerAccountBook customerAccountBook,
                                      HyDriverAccountBook driverAccountBook,
                                      HyCarrierAccountBook carrierAccountBook) {
        HyBill hyBill = payBillData.getHyBill();
        //货主多级账簿
        String customerDbAccNo = customerAccountBook.getAccNo();
        String customerDbAccName = customerAccountBook.getLogAccName();
        String customerDbLogAccNo = customerAccountBook.getLogAccNo();

        //分公司子账号
        String companyAccNo = company.getAccNo();
        String companyAccName = company.getAccName();
        String companyLogAccNo = "";

        //司机账簿
        String driverAccNo = driverAccountBook.getAccNo();
        String driverAccName = driverAccountBook.getLogAccName();
        String driverLogAccNo = driverAccountBook.getLogAccNo();

        HyCustomerBill customerBill = payBillData.getCustomerBill();
        customerBill.setDbaccno(customerDbAccNo);
        customerBill.setDbaccname(customerDbAccName);
        customerBill.setDblogaccno(customerDbLogAccNo);
        customerBill.setDbProv(customerAccountBook.getProv());
        customerBill.setCraccno(companyAccNo);
        customerBill.setCraccname(companyAccName);
        customerBill.setCrlogaccno(companyLogAccNo);
        customerBill.setCrProv(company.getProv());

        HyShippingNoteBill shippingNoteBill = payBillData.getShippingNoteBill();
        //分公司
        shippingNoteBill.setDbaccno(companyAccNo);
        shippingNoteBill.setDbaccname(companyAccName);
        shippingNoteBill.setDblogaccno(companyLogAccNo);
        shippingNoteBill.setDbProv(company.getProv());

        shippingNoteBill.setCraccno(driverAccNo);
        shippingNoteBill.setCraccname(driverAccName);
        shippingNoteBill.setCrlogaccno(driverLogAccNo);
        shippingNoteBill.setCrProv(driverAccountBook.getProv());
        shippingNoteBill.setBankCode("ABOC");

        //添加司机流水单
        HyDriverBill driverBill = payBillData.getDriverBill();
        driverBill.setDbaccno(companyAccNo);
        driverBill.setDbaccname(companyAccName);
        driverBill.setDblogaccno(companyLogAccNo);

        driverBill.setCraccno(driverAccNo);
        driverBill.setCraccname(driverAccName);
        driverBill.setCrlogaccno(driverLogAccNo);

        //是否车队长代收
        if ("1".equals(hyBill.getIzCarrierPay())) {
            //添加车队长流水单 (司机支付给车队长)
            String carrierAccNo = carrierAccountBook.getAccNo();
            String carrierAccName = carrierAccountBook.getLogAccName();
            String carrierLogAccNo = carrierAccountBook.getLogAccNo();

            HyCarrierBill carrierBill = payBillData.getCarrierBill();
            carrierBill.setDbaccno(driverAccNo);
            carrierBill.setDbaccname(driverAccName);
            carrierBill.setDblogaccno(driverLogAccNo);
            carrierBill.setDbProv(driverAccountBook.getProv());
            carrierBill.setCraccno(carrierAccNo);
            carrierBill.setCraccname(carrierAccName);
            carrierBill.setCrlogaccno(carrierLogAccNo);
            carrierBill.setCrProv(carrierAccountBook.getProv());
            carrierBill.setCrBankCode("");
            payBillData.setCarrierBill(carrierBill);
        }
        return payBillData;
    }

    public PayBillData setBillPayData(PayBillData payBillData ,
                                      HyCompany company,
                                      HyPlatformAccountBook platformAccountBook,
                                      HyDriverAccountBook driverAccountBook,
                                      HyCarrierAccountBook carrierAccountBook) {
        HyBill hyBill = payBillData.getHyBill();
        //平台多级账簿
        String platformDbAccNo = platformAccountBook.getAccNo();
        String platformrDbAccName = platformAccountBook.getLogAccName();
        String platformDbLogAccNo = platformAccountBook.getLogAccNo();

        //分公司子账号
        String companyAccNo = company.getAccNo();
        String companyAccName = company.getAccName();
        String companyLogAccNo = "";

        //司机账簿
        String driverAccNo = driverAccountBook.getAccNo();
        String driverAccName = driverAccountBook.getLogAccName();
        String driverLogAccNo = driverAccountBook.getLogAccNo();

        HyCustomerBill customerBill = payBillData.getCustomerBill();
        customerBill.setDbaccno(platformDbAccNo);
        customerBill.setDbaccname(platformrDbAccName);
        customerBill.setDblogaccno(platformDbLogAccNo);
        customerBill.setDbProv(platformAccountBook.getProv());
        customerBill.setCraccno(companyAccNo);
        customerBill.setCraccname(companyAccName);
        customerBill.setCrlogaccno(companyLogAccNo);
        customerBill.setCrProv(company.getProv());

        HyShippingNoteBill shippingNoteBill = payBillData.getShippingNoteBill();
        //分公司
        shippingNoteBill.setDbaccno(companyAccNo);
        shippingNoteBill.setDbaccname(companyAccName);
        shippingNoteBill.setDblogaccno(companyLogAccNo);
        shippingNoteBill.setDbProv(company.getProv());

        shippingNoteBill.setCraccno(driverAccNo);
        shippingNoteBill.setCraccname(driverAccName);
        shippingNoteBill.setCrlogaccno(driverLogAccNo);
        shippingNoteBill.setCrProv(driverAccountBook.getProv());
        shippingNoteBill.setBankCode("ABOC");

        //添加司机流水单
        HyDriverBill driverBill = payBillData.getDriverBill();
        driverBill.setDbaccno(companyAccNo);
        driverBill.setDbaccname(companyAccName);
        driverBill.setDblogaccno(companyLogAccNo);

        driverBill.setCraccno(driverAccNo);
        driverBill.setCraccname(driverAccName);
        driverBill.setCrlogaccno(driverLogAccNo);

        //是否车队长代收
        if ("1".equals(hyBill.getIzCarrierPay())) {
            //添加车队长流水单 (司机支付给车队长)
            String carrierAccNo = carrierAccountBook.getAccNo();
            String carrierAccName = carrierAccountBook.getLogAccName();
            String carrierLogAccNo = carrierAccountBook.getLogAccNo();

            HyCarrierBill carrierBill = payBillData.getCarrierBill();
            carrierBill.setDbaccno(driverAccNo);
            carrierBill.setDbaccname(driverAccName);
            carrierBill.setDblogaccno(driverLogAccNo);
            carrierBill.setDbProv(driverAccountBook.getProv());
            carrierBill.setCraccno(carrierAccNo);
            carrierBill.setCraccname(carrierAccName);
            carrierBill.setCrlogaccno(carrierLogAccNo);
            carrierBill.setCrProv(carrierAccountBook.getProv());
            carrierBill.setCrBankCode("");
            payBillData.setCarrierBill(carrierBill);
        }
        return payBillData;
    }

    //设置支付账户信息
    public void setBillPayDatasAccInfo(List<PayBillData> payDatas,
                                       HyCustomerAccountBook customerAccountBook,
                                       Map<String, HyCompany> companyMaps,
                                       Map<String, HyDriverAccountBook> driverAccountBookMaps,
                                       Map<String, HyCarrierAccountBook> carrierAccountBookHashMaps
                                ) {
        for (PayBillData payData : payDatas) {
            HyBill hyBill = payData.getHyBill();
            HyShippingNote hyShippingNote = payData.getShippingNote();
            HyCompany company = companyMaps.get(hyShippingNote.getCompanyId());
            HyDriverAccountBook driverAccountBook = driverAccountBookMaps.get(hyShippingNote.getDriverId());
            HyCarrierAccountBook carrierAccountBook = null;
            if ("1".equals(hyBill.getIzCarrierPay())) {
                carrierAccountBook = carrierAccountBookHashMaps.get(hyShippingNote.getCarrierId());
            }
            this.setBillPayData(payData, company, customerAccountBook, driverAccountBook, carrierAccountBook);
        }
    }



    public void setBillPayDatasAccInfo(List<PayBillData> payDatas,
                                       HyPlatformAccountBook accountBook,
                                       Map<String, HyCompany> companyMaps,
                                       Map<String, HyDriverAccountBook> driverAccountBookMaps,
                                       Map<String, HyCarrierAccountBook> carrierAccountBookHashMaps) {
        for (PayBillData payData : payDatas) {
            HyBill hyBill = payData.getHyBill();
            HyShippingNote hyShippingNote = payData.getShippingNote();
            HyCompany company = companyMaps.get(hyShippingNote.getCompanyId());
            HyDriverAccountBook driverAccountBook = driverAccountBookMaps.get(hyShippingNote.getDriverId());
            HyCarrierAccountBook carrierAccountBook = null;
            if ("1".equals(hyBill.getIzCarrierPay())) {
                carrierAccountBook = carrierAccountBookHashMaps.get(hyShippingNote.getCarrierId());
            }
            this.setBillPayData(payData, company, accountBook, driverAccountBook, carrierAccountBook);
        }
    }

    @Transactional
    public void setBillRePayDatas(List<PayBillData> payDatas) {
        Map<String, HyCompany> companyMaps = this.getCompanyMaps();
        List<HyBill> bills = new ArrayList<>();
        for (PayBillData payData : payDatas) {
            HyBill hyBill = payData.getHyBill();
            hyBill.setPayStatus("5");
            HyCustomerBill customerBill = payData.getCustomerBill();
            HyShippingNoteBill shippingNoteBill = payData.getShippingNoteBill();
            HyDriverBill driverBill = payData.getDriverBill();
            HyCompany company = companyMaps.get(shippingNoteBill.getCompanyId());
            this.setBillRePayData(company,customerBill,shippingNoteBill,driverBill);
            bills.add(hyBill);
        }
        hyBillService.updateBatchById(bills);
    }

    public void setBillRePayData(HyCompany company , HyCustomerBill customerBill , HyShippingNoteBill shippingNoteBill , HyDriverBill driverBill){
        //分公司子账号
        String companyAccNo = company.getAccNo();
        String companyAccName = company.getAccName();
        String companyLogAccNo = "";
        if ("5".equals(customerBill.getRespSource())) {
            //重新设置分公司支付信息，分公司信息可能存在填写错误的情况
            customerBill.setCraccno(companyAccNo);
            customerBill.setCraccname(companyAccName);
            customerBill.setCrlogaccno(companyLogAccNo);
            customerBill.setCrProv(company.getProv());
        }
        if ("5".equals(shippingNoteBill.getRespSource())) {
            //分公司
            shippingNoteBill.setDbaccno(companyAccNo);
            shippingNoteBill.setDbaccname(companyAccName);
            shippingNoteBill.setDblogaccno(companyLogAccNo);
            shippingNoteBill.setDbProv(company.getProv());

            driverBill.setDbaccno(companyAccNo);
            driverBill.setDbaccname(companyAccName);
            driverBill.setDblogaccno(companyLogAccNo);
        }
    }
    //endregion

}
